home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / app / rect_select.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-05-08  |  18.9 KB  |  768 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <stdlib.h>
  22.  
  23. #include <gtk/gtk.h>
  24. #include <gdk/gdkkeysyms.h>
  25.  
  26. #include "apptypes.h"
  27.  
  28. #include "appenv.h"
  29. #include "gdisplay.h"
  30. #include "gimage_mask.h"
  31. #include "edit_selection.h"
  32. #include "floating_sel.h"
  33. #include "rect_select.h"
  34. #include "rect_selectP.h"
  35. #include "selection_options.h"
  36. #include "cursorutil.h"
  37.  
  38. #include "libgimp/gimpunitmenu.h"
  39.  
  40. #include "libgimp/gimpintl.h"
  41.  
  42.  
  43. #define STATUSBAR_SIZE 128
  44.  
  45.  
  46. /*  the rectangular selection tool options  */
  47. static SelectionOptions *rect_options = NULL;
  48.  
  49. /*  in gimp, ellipses are rectangular, too ;)  */
  50. extern SelectionOptions *ellipse_options;
  51. extern void ellipse_select (GimpImage *gimage,
  52.                 gint       x,
  53.                 gint       y,
  54.                 gint       w,
  55.                 gint       h,
  56.                 SelectOps  op,
  57.                 gboolean   antialias,
  58.                 gboolean   feather,
  59.                 gdouble    feather_radius);
  60.  
  61. static void selection_tool_update_op_state (RectSelect *rect_sel,
  62.                         gint        x,
  63.                         gint        y,
  64.                         gint        state, 
  65.                         GDisplay   *gdisp);
  66.  
  67. /*************************************/
  68. /*  Rectangular selection apparatus  */
  69.  
  70. void
  71. rect_select (GimpImage *gimage,
  72.          gint       x,
  73.          gint       y,
  74.          gint       w,
  75.          gint       h,
  76.          SelectOps  op,
  77.          gboolean   feather,
  78.          gdouble    feather_radius)
  79. {
  80.   Channel *new_mask;
  81.  
  82.   /*  if applicable, replace the current selection  */
  83.   if (op == SELECTION_REPLACE)
  84.     gimage_mask_clear (gimage);
  85.   else
  86.     gimage_mask_undo (gimage);
  87.  
  88.   /*  if feathering for rect, make a new mask with the
  89.    *  rectangle and feather that with the old mask
  90.    */
  91.   if (feather)
  92.     {
  93.       new_mask = channel_new_mask (gimage, gimage->width, gimage->height);
  94.       channel_combine_rect (new_mask, ADD, x, y, w, h);
  95.       channel_feather (new_mask, gimage_get_mask (gimage),
  96.                feather_radius,
  97.                feather_radius,
  98.                op, 0, 0);
  99.       channel_delete (new_mask);
  100.     }
  101.   else if (op == SELECTION_INTERSECT)
  102.     {
  103.       new_mask = channel_new_mask (gimage, gimage->width, gimage->height);
  104.       channel_combine_rect (new_mask, ADD, x, y, w, h);
  105.       channel_combine_mask (gimage_get_mask (gimage), new_mask, op, 0, 0);
  106.       channel_delete (new_mask);
  107.     }
  108.   else
  109.     channel_combine_rect (gimage_get_mask (gimage), op, x, y, w, h);
  110. }
  111.  
  112. void
  113. rect_select_button_press (Tool           *tool,
  114.               GdkEventButton *bevent,
  115.               gpointer        gdisp_ptr)
  116. {
  117.   GDisplay   *gdisp;
  118.   RectSelect *rect_sel;
  119.   gchar       select_mode[STATUSBAR_SIZE];
  120.   gint        x, y;
  121.   GimpUnit    unit = GIMP_UNIT_PIXEL;
  122.   gdouble     unit_factor;
  123.  
  124.   gdisp = (GDisplay *) gdisp_ptr;
  125.   rect_sel = (RectSelect *) tool->private;
  126.  
  127.   gdisplay_untransform_coords (gdisp, 
  128.                                bevent->x, bevent->y, &x, &y, TRUE, FALSE);
  129.  
  130.   rect_sel->x = x;
  131.   rect_sel->y = y;
  132.   switch (tool->type)
  133.     {
  134.     case RECT_SELECT:
  135.       rect_sel->fixed_size   = rect_options->fixed_size;
  136.       rect_sel->fixed_width  = rect_options->fixed_width;
  137.       rect_sel->fixed_height = rect_options->fixed_height;
  138.       unit = rect_options->fixed_unit;
  139.       break;
  140.     case ELLIPSE_SELECT:
  141.       rect_sel->fixed_size   = ellipse_options->fixed_size;
  142.       rect_sel->fixed_width  = ellipse_options->fixed_width;
  143.       rect_sel->fixed_height = ellipse_options->fixed_height;
  144.       unit = ellipse_options->fixed_unit;
  145.       break;
  146.     default:
  147.       break;
  148.     }
  149.  
  150.   switch (unit)
  151.     {
  152.     case GIMP_UNIT_PIXEL:
  153.       break;
  154.     case GIMP_UNIT_PERCENT:
  155.       rect_sel->fixed_width =
  156.     gdisp->gimage->width * rect_sel->fixed_width / 100;
  157.       rect_sel->fixed_height =
  158.     gdisp->gimage->height * rect_sel->fixed_height / 100;
  159.       break;
  160.     default:
  161.       unit_factor = gimp_unit_get_factor (unit);
  162.       rect_sel->fixed_width =
  163.      rect_sel->fixed_width * gdisp->gimage->xresolution / unit_factor;
  164.       rect_sel->fixed_height =
  165.     rect_sel->fixed_height * gdisp->gimage->yresolution / unit_factor;
  166.       break;
  167.     }
  168.  
  169.   rect_sel->fixed_width  = MAX (1, rect_sel->fixed_width);
  170.   rect_sel->fixed_height = MAX (1, rect_sel->fixed_height);
  171.  
  172.   rect_sel->w = 0;
  173.   rect_sel->h = 0;
  174.  
  175.   rect_sel->center = FALSE;
  176.  
  177.   gdk_pointer_grab (gdisp->canvas->window, FALSE,
  178.             GDK_POINTER_MOTION_HINT_MASK |
  179.             GDK_BUTTON1_MOTION_MASK |
  180.             GDK_BUTTON_RELEASE_MASK,
  181.             NULL, NULL, bevent->time);
  182.  
  183.   tool->state = ACTIVE;
  184.   tool->gdisp_ptr = gdisp_ptr;
  185.  
  186.   switch (rect_sel->op)
  187.     {
  188.     case SELECTION_MOVE_MASK:
  189.       init_edit_selection (tool, gdisp_ptr, bevent, EDIT_MASK_TRANSLATE);
  190.       return;
  191.     case SELECTION_MOVE:
  192.       init_edit_selection (tool, gdisp_ptr, bevent, EDIT_MASK_TO_LAYER_TRANSLATE);
  193.       return;
  194.     default:
  195.       break;
  196.     }
  197.  
  198.   /* initialize the statusbar display */
  199.   rect_sel->context_id =
  200.     gtk_statusbar_get_context_id (GTK_STATUSBAR (gdisp->statusbar), "selection");
  201.   switch (rect_sel->op)
  202.     {
  203.     case SELECTION_ADD:
  204.       g_snprintf (select_mode, STATUSBAR_SIZE, _("Selection: ADD"));
  205.       break;
  206.     case SELECTION_SUB:
  207.       g_snprintf (select_mode, STATUSBAR_SIZE, _("Selection: SUBTRACT"));
  208.       break;
  209.     case SELECTION_INTERSECT:
  210.       g_snprintf (select_mode, STATUSBAR_SIZE, _("Selection: INTERSECT"));
  211.       break;
  212.     case SELECTION_REPLACE:
  213.       g_snprintf (select_mode, STATUSBAR_SIZE, _("Selection: REPLACE"));
  214.       break;
  215.     default:
  216.       break;
  217.     }
  218.   gtk_statusbar_push (GTK_STATUSBAR (gdisp->statusbar),
  219.               rect_sel->context_id, select_mode);
  220.  
  221.   draw_core_start (rect_sel->core, gdisp->canvas->window, tool);
  222. }
  223.  
  224. void
  225. rect_select_button_release (Tool           *tool,
  226.                 GdkEventButton *bevent,
  227.                 gpointer        gdisp_ptr)
  228. {
  229.   RectSelect *rect_sel;
  230.   GDisplay   *gdisp;
  231.   gint x1, y1;
  232.   gint x2, y2;
  233.   gint w, h;
  234.  
  235.   gdisp = (GDisplay *) gdisp_ptr;
  236.   rect_sel = (RectSelect *) tool->private;
  237.  
  238.   gdk_pointer_ungrab (bevent->time);
  239.   gdk_flush ();
  240.  
  241.   gtk_statusbar_pop (GTK_STATUSBAR (gdisp->statusbar), rect_sel->context_id);
  242.  
  243.   draw_core_stop (rect_sel->core, tool);
  244.   tool->state = INACTIVE;
  245.  
  246.   /*  First take care of the case where the user "cancels" the action  */
  247.   if (! (bevent->state & GDK_BUTTON3_MASK))
  248.     {
  249.       x1 = (rect_sel->w < 0) ? rect_sel->x + rect_sel->w : rect_sel->x;
  250.       y1 = (rect_sel->h < 0) ? rect_sel->y + rect_sel->h : rect_sel->y;
  251.       w = (rect_sel->w < 0) ? -rect_sel->w : rect_sel->w;
  252.       h = (rect_sel->h < 0) ? -rect_sel->h : rect_sel->h;
  253.  
  254.      if ((!w || !h) && !rect_sel->fixed_size)
  255.     {
  256.       /*  If there is a floating selection, anchor it  */
  257.       if (gimage_floating_sel (gdisp->gimage))
  258.         floating_sel_anchor (gimage_floating_sel (gdisp->gimage));
  259.       /*  Otherwise, clear the selection mask  */
  260.       else
  261.         gimage_mask_clear (gdisp->gimage);
  262.       
  263.       gdisplays_flush ();
  264.       return;
  265.     }
  266.       
  267.       x2 = x1 + w;
  268.       y2 = y1 + h;
  269.  
  270.       switch (tool->type)
  271.     {
  272.     case RECT_SELECT:
  273.       rect_select (gdisp->gimage,
  274.                x1, y1, (x2 - x1), (y2 - y1),
  275.                rect_sel->op,
  276.                rect_options->feather,
  277.                rect_options->feather_radius);
  278.       break;
  279.       
  280.     case ELLIPSE_SELECT:
  281.       ellipse_select (gdisp->gimage,
  282.               x1, y1, (x2 - x1), (y2 - y1),
  283.               rect_sel->op,
  284.               ellipse_options->antialias,
  285.               ellipse_options->feather,
  286.               ellipse_options->feather_radius);
  287.       break;
  288.     default:
  289.       break;
  290.     }
  291.       
  292.       /*  show selection on all views  */
  293.       gdisplays_flush ();
  294.    }
  295. }
  296.  
  297. void
  298. rect_select_motion (Tool           *tool,
  299.             GdkEventMotion *mevent,
  300.             gpointer        gdisp_ptr)
  301. {
  302.   RectSelect *rect_sel;
  303.   GDisplay   *gdisp;
  304.   gchar   size[STATUSBAR_SIZE];
  305.   gint    ox, oy;
  306.   gint    x, y;
  307.   gint    w, h, s;
  308.   gint    tw, th;
  309.   gdouble ratio;
  310.  
  311.   gdisp = (GDisplay *) gdisp_ptr;
  312.   rect_sel = (RectSelect *) tool->private;
  313.  
  314.   /*  needed for immediate cursor update on modifier event  */
  315.   rect_sel->current_x = mevent->x;
  316.   rect_sel->current_y = mevent->y;
  317.  
  318.   if (tool->state != ACTIVE)
  319.     return;
  320.  
  321.   if (rect_sel->op == SELECTION_ANCHOR)
  322.     {
  323.       rect_sel->op = SELECTION_REPLACE;
  324.  
  325.       rect_select_cursor_update (tool, mevent, gdisp_ptr);
  326.     }
  327.  
  328.   draw_core_pause (rect_sel->core, tool);
  329.  
  330.   /* Calculate starting point */
  331.  
  332.   if (rect_sel->center)
  333.     {
  334.       ox = rect_sel->x + rect_sel->w / 2;
  335.       oy = rect_sel->y + rect_sel->h / 2;
  336.     }
  337.   else
  338.     {
  339.       ox = rect_sel->x;
  340.       oy = rect_sel->y;
  341.     }
  342.  
  343.   gdisplay_untransform_coords (gdisp, 
  344.                                mevent->x, mevent->y, &x, &y, TRUE, FALSE);
  345.  
  346.   if (rect_sel->fixed_size)
  347.     {
  348.       if (mevent->state & GDK_SHIFT_MASK)
  349.     {
  350.       ratio = (double)(rect_sel->fixed_height /
  351.                (double)rect_sel->fixed_width);
  352.       tw = x - ox;
  353.       th = y - oy;
  354.       /* 
  355.        * This is probably an inefficient way to do it, but it gives
  356.        * nicer, more predictable results than the original agorithm
  357.        */
  358.  
  359.       if ((abs(th) < (ratio * abs(tw))) && (abs(tw) > (abs(th) / ratio)))
  360.         {
  361.           w = tw;
  362.           h = (int)(tw * ratio);
  363.           /* h should have the sign of th */
  364.           if ((th < 0 && h > 0) || (th > 0 && h < 0))
  365.         h = -h;
  366.         } 
  367.       else 
  368.         {
  369.           h = th;
  370.           w = (int)(th / ratio);
  371.           /* w should have the sign of tw */
  372.           if ((tw < 0 && w > 0) || (tw > 0 && w < 0))
  373.         w = -w;
  374.         }
  375.     }
  376.       else
  377.     {
  378.       w = (x - ox > 0 ? rect_sel->fixed_width  : -rect_sel->fixed_width);
  379.       h = (y - oy > 0 ? rect_sel->fixed_height : -rect_sel->fixed_height);
  380.     }
  381.     }
  382.   else
  383.     {
  384.       w = (x - ox);
  385.       h = (y - oy);
  386.     }
  387.  
  388.   /*  If the shift key is down, then make the rectangle square (or ellipse circular) */
  389.   if ((mevent->state & GDK_SHIFT_MASK) && !rect_sel->fixed_size)
  390.     {
  391.       s = MAX (abs (w), abs (h));
  392.       
  393.       if (w < 0)
  394.     w = -s;
  395.       else
  396.     w = s;
  397.  
  398.       if (h < 0)
  399.     h = -s;
  400.       else
  401.     h = s;
  402.     }
  403.  
  404.   /*  If the control key is down, create the selection from the center out */
  405.   if (mevent->state & GDK_CONTROL_MASK)
  406.     {
  407.       if (rect_sel->fixed_size) 
  408.     {
  409.           if (mevent->state & GDK_SHIFT_MASK) 
  410.             {
  411.               rect_sel->x = ox - w;
  412.               rect_sel->y = oy - h;
  413.               rect_sel->w = w * 2;
  414.               rect_sel->h = h * 2;
  415.             }
  416.           else
  417.             {
  418.               rect_sel->x = ox - w / 2;
  419.               rect_sel->y = oy - h / 2;
  420.               rect_sel->w = w;
  421.               rect_sel->h = h;
  422.             }
  423.     } 
  424.       else 
  425.     {
  426.       w = abs(w);
  427.       h = abs(h);
  428.       
  429.       rect_sel->x = ox - w;
  430.       rect_sel->y = oy - h;
  431.       rect_sel->w = 2 * w + 1;
  432.       rect_sel->h = 2 * h + 1;
  433.     }
  434.       rect_sel->center = TRUE;
  435.     }
  436.   else
  437.     {
  438.       rect_sel->x = ox;
  439.       rect_sel->y = oy;
  440.       rect_sel->w = w;
  441.       rect_sel->h = h;
  442.  
  443.       rect_sel->center = FALSE;
  444.     }
  445.  
  446.   gtk_statusbar_pop (GTK_STATUSBAR (gdisp->statusbar), rect_sel->context_id);
  447.   if (gdisp->dot_for_dot)
  448.     {
  449.       g_snprintf (size, STATUSBAR_SIZE, gdisp->cursor_format_str,
  450.           _("Selection: "), abs(rect_sel->w), " x ", abs(rect_sel->h));
  451.     }
  452.   else /* show real world units */
  453.     {
  454.       gdouble unit_factor = gimp_unit_get_factor (gdisp->gimage->unit);
  455.  
  456.       g_snprintf (size, STATUSBAR_SIZE, gdisp->cursor_format_str,
  457.           _("Selection: "),
  458.           (gdouble) abs(rect_sel->w) * unit_factor /
  459.           gdisp->gimage->xresolution,
  460.           " x ",
  461.           (gdouble) abs(rect_sel->h) * unit_factor /
  462.           gdisp->gimage->yresolution);
  463.     }
  464.   gtk_statusbar_push (GTK_STATUSBAR (gdisp->statusbar), rect_sel->context_id,
  465.               size);
  466.  
  467.   draw_core_resume (rect_sel->core, tool);
  468. }
  469.  
  470. void
  471. rect_select_draw (Tool *tool)
  472. {
  473.   GDisplay   *gdisp;
  474.   RectSelect *rect_sel;
  475.   gint x1, y1;
  476.   gint x2, y2;
  477.  
  478.   gdisp = (GDisplay *) tool->gdisp_ptr;
  479.   rect_sel = (RectSelect *) tool->private;
  480.  
  481.   x1 = MIN (rect_sel->x, rect_sel->x + rect_sel->w);
  482.   y1 = MIN (rect_sel->y, rect_sel->y + rect_sel->h);
  483.   x2 = MAX (rect_sel->x, rect_sel->x + rect_sel->w);
  484.   y2 = MAX (rect_sel->y, rect_sel->y + rect_sel->h);
  485.  
  486.   gdisplay_transform_coords (gdisp, x1, y1, &x1, &y1, FALSE);
  487.   gdisplay_transform_coords (gdisp, x2, y2, &x2, &y2, FALSE);
  488.  
  489.   if (x2 > x1 && y2 > y1)
  490.     gdk_draw_rectangle (rect_sel->core->win,
  491.                         rect_sel->core->gc, FALSE,
  492.                         x1, y1, 
  493.                         x2 - x1 - 1, y2 - y1 - 1);
  494. }
  495.  
  496. static void
  497. selection_tool_update_op_state (RectSelect *rect_sel,
  498.                 gint        x,
  499.                 gint        y,
  500.                 gint        state,  
  501.                 GDisplay   *gdisp)
  502. {
  503.   Layer *layer;
  504.   Layer *floating_sel;
  505.   gint   tx, ty;
  506.  
  507.   if (active_tool->state == ACTIVE)
  508.     return;
  509.  
  510.   gdisplay_untransform_coords (gdisp, x, y, &tx, &ty, FALSE, FALSE);
  511.  
  512.   layer = gimage_pick_correlate_layer (gdisp->gimage, tx, ty);
  513.   floating_sel = gimage_floating_sel (gdisp->gimage);
  514.  
  515.   if (state & GDK_MOD1_MASK &&
  516.       !gimage_mask_is_empty (gdisp->gimage))
  517.     {
  518.       rect_sel->op = SELECTION_MOVE_MASK; /* move just the selection mask */
  519.     }
  520.   else if (!(state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) &&
  521.        layer &&
  522.        (layer == floating_sel ||
  523.         (gdisplay_mask_value (gdisp, x, y) &&
  524.          floating_sel == NULL)))
  525.     {
  526.       rect_sel->op = SELECTION_MOVE;      /* move the selection */
  527.     }
  528.   else if ((state & GDK_SHIFT_MASK) &&
  529.        !(state & GDK_CONTROL_MASK))
  530.     {
  531.       rect_sel->op = SELECTION_ADD;       /* add to the selection */
  532.     }
  533.   else if ((state & GDK_CONTROL_MASK) &&
  534.        !(state & GDK_SHIFT_MASK))
  535.     {
  536.       rect_sel->op = SELECTION_SUB;       /* subtract from the selection */
  537.     }
  538.   else if ((state & GDK_CONTROL_MASK) &&
  539.        (state & GDK_SHIFT_MASK))
  540.     {
  541.       rect_sel->op = SELECTION_INTERSECT; /* intersect with selection */
  542.     }
  543.   else if (floating_sel)
  544.     {
  545.       rect_sel->op = SELECTION_ANCHOR;    /* anchor the selection */
  546.     }
  547.   else
  548.     {
  549.       rect_sel->op = SELECTION_REPLACE;   /* replace the selection */
  550.     }
  551. }
  552.  
  553. void
  554. rect_select_oper_update  (Tool           *tool,
  555.               GdkEventMotion *mevent,
  556.               gpointer        gdisp_ptr)
  557. {
  558.   RectSelect *rect_sel;
  559.  
  560.   rect_sel = (RectSelect *) tool->private;
  561.  
  562.   rect_sel->current_x = mevent->x;
  563.   rect_sel->current_y = mevent->y;
  564.  
  565.   selection_tool_update_op_state (rect_sel,
  566.                   rect_sel->current_x,
  567.                   rect_sel->current_y,
  568.                   mevent->state, gdisp_ptr);
  569. }
  570.  
  571. void
  572. rect_select_modifier_update (Tool        *tool,
  573.                  GdkEventKey *kevent,
  574.                  gpointer     gdisp_ptr)
  575. {
  576.   RectSelect *rect_sel;
  577.   gint state;
  578.  
  579.   state = kevent->state;
  580.  
  581.   switch (kevent->keyval)
  582.     {
  583.     case GDK_Alt_L: case GDK_Alt_R:
  584.       if (state & GDK_MOD1_MASK)
  585.     state &= ~GDK_MOD1_MASK;
  586.       else
  587.     state |= GDK_MOD1_MASK;
  588.       break;
  589.  
  590.     case GDK_Shift_L: case GDK_Shift_R:
  591.       if (state & GDK_SHIFT_MASK)
  592.     state &= ~GDK_SHIFT_MASK;
  593.       else
  594.     state |= GDK_SHIFT_MASK;
  595.       break;
  596.  
  597.     case GDK_Control_L: case GDK_Control_R:
  598.       if (state & GDK_CONTROL_MASK)
  599.     state &= ~GDK_CONTROL_MASK;
  600.       else
  601.     state |= GDK_CONTROL_MASK;
  602.       break;
  603.     }
  604.  
  605.   rect_sel = (RectSelect *) tool->private;
  606.   selection_tool_update_op_state (rect_sel,
  607.                   rect_sel->current_x,
  608.                   rect_sel->current_y,
  609.                   state, gdisp_ptr);
  610. }
  611.  
  612. void
  613. rect_select_arrow_keys (Tool        *tool,
  614.                         GdkEventKey *kevent,
  615.                         gpointer     gdisp_ptr)
  616. {
  617.   RectSelect *rect_sel;
  618.   GDisplay   *gdisp;
  619.  
  620.   rect_sel = (RectSelect *) tool->private;
  621.   gdisp = (GDisplay *) gdisp_ptr;
  622.  
  623.   if ((rect_sel->op == SELECTION_MOVE_MASK) ||
  624.       (rect_sel->op == SELECTION_MOVE && gimage_floating_sel (gdisp->gimage)))
  625.     {
  626.       edit_sel_arrow_keys_func (tool, kevent, gdisp_ptr);
  627.     }
  628. }
  629.  
  630. void
  631. rect_select_cursor_update (Tool           *tool,
  632.                GdkEventMotion *mevent,
  633.                gpointer        gdisp_ptr)
  634. {
  635.   RectSelect *rect_sel;
  636.   GDisplay   *gdisp;
  637.  
  638.   rect_sel = (RectSelect *) tool->private;
  639.   gdisp = (GDisplay *) gdisp_ptr;
  640.  
  641.   switch (rect_sel->op)
  642.     {
  643.     case SELECTION_ADD:
  644.       gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
  645.                     tool->type,
  646.                     CURSOR_MODIFIER_PLUS,
  647.                     FALSE);
  648.       break;
  649.     case SELECTION_SUB:
  650.       gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
  651.                     tool->type,
  652.                     CURSOR_MODIFIER_MINUS,
  653.                     FALSE);
  654.       break;
  655.     case SELECTION_INTERSECT: 
  656.       gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
  657.                     tool->type,
  658.                     CURSOR_MODIFIER_INTERSECT,
  659.                     FALSE);
  660.       break;
  661.     case SELECTION_REPLACE:
  662.       gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
  663.                     tool->type,
  664.                     CURSOR_MODIFIER_NONE,
  665.                     FALSE);
  666.       break;
  667.     case SELECTION_MOVE_MASK:
  668.       gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
  669.                     tool->type,
  670.                     CURSOR_MODIFIER_MOVE,
  671.                     FALSE);
  672.       break;
  673.     case SELECTION_MOVE:
  674.       gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
  675.                     MOVE,
  676.                     CURSOR_MODIFIER_NONE,
  677.                     FALSE);
  678.       break;
  679.     case SELECTION_ANCHOR:
  680.       gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
  681.                     tool->type,
  682.                     CURSOR_MODIFIER_ANCHOR,
  683.                     FALSE);
  684.       break;
  685.     }
  686. }
  687.  
  688. void
  689. rect_select_control (Tool       *tool,
  690.              ToolAction  action,
  691.              gpointer    gdisp_ptr)
  692. {
  693.   RectSelect *rect_sel;
  694.  
  695.   rect_sel = (RectSelect *) tool->private;
  696.  
  697.   switch (action)
  698.     {
  699.     case PAUSE:
  700.       draw_core_pause (rect_sel->core, tool);
  701.       break;
  702.  
  703.     case RESUME:
  704.       draw_core_resume (rect_sel->core, tool);
  705.       break;
  706.  
  707.     case HALT:
  708.       draw_core_stop (rect_sel->core, tool);
  709.       break;
  710.  
  711.     default:
  712.       break;
  713.     }
  714. }
  715.  
  716. static void
  717. rect_select_options_reset (void)
  718. {
  719.   selection_options_reset (rect_options);
  720. }
  721.  
  722. Tool *
  723. tools_new_rect_select (void)
  724. {
  725.   Tool * tool;
  726.   RectSelect * private;
  727.  
  728.   /*  The tool options  */
  729.   if (! rect_options)
  730.     {
  731.       rect_options =
  732.     selection_options_new (RECT_SELECT, rect_select_options_reset);
  733.       tools_register (RECT_SELECT, (ToolOptions *) rect_options);
  734.     }
  735.  
  736.   tool = tools_new_tool (RECT_SELECT);
  737.   private = g_new0 (RectSelect, 1);
  738.  
  739.   private->core = draw_core_new (rect_select_draw);
  740.   private->x = private->y = 0;
  741.   private->w = private->h = 0;
  742.   private->op = SELECTION_REPLACE;
  743.  
  744.   tool->private = (void *) private;
  745.  
  746.   tool->button_press_func   = rect_select_button_press;
  747.   tool->button_release_func = rect_select_button_release;
  748.   tool->motion_func         = rect_select_motion;
  749.   tool->arrow_keys_func     = rect_select_arrow_keys;
  750.   tool->modifier_key_func   = rect_select_modifier_update;
  751.   tool->cursor_update_func  = rect_select_cursor_update;
  752.   tool->oper_update_func    = rect_select_oper_update;
  753.   tool->control_func        = rect_select_control;
  754.  
  755.   return tool;
  756. }
  757.  
  758. void
  759. tools_free_rect_select (Tool *tool)
  760. {
  761.   RectSelect * rect_sel;
  762.  
  763.   rect_sel = (RectSelect *) tool->private;
  764.  
  765.   draw_core_free (rect_sel->core);
  766.   g_free (rect_sel);
  767. }
  768.